package ServiceNetIO

import (
	LogUtils "IMServices/LogService"
	"fmt"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"strings"
	"time"

	"log"
	"net"
)

var MsgChannel chan RequestBuffer

var MsgSendChannel chan RequestBuffer

var ServerMap map[string]UserServiceServer

var QuitChannel chan bool

const (
	ServerType        = iota
	ServerTypeLogin   = iota
	ServerTypeStatus  = iota
	ServerTypeMessage = iota
)

type MessageRequest struct {
	Header     []byte
	ServerName string
	OrderId    int64
	EncodeType string
	Body       []byte
}

type ServerClient struct {
	Listen        UserServiceServer
	LoginServer   UserServiceServer
	StatusServer  UserServiceServer
	MessageServer UserServiceServer
}

//type UserServiceServer struct {
//	orderSize  int64
//	Listen     net.Listener
//	Client     UserServiceInterfaceClient
//	Ctx        context.Context
//	CancelFunc context.CancelFunc
//	SenderCtx  context.Context
//	server     *grpc.Server
//}

type UserServiceServer struct {
	orderSize  int64
	Listen     net.Listener
	Client     UserServiceInterfaceClient
	Ctx        context.Context
	CancelFunc context.CancelFunc
	SenderCtx  context.Context
	server     *grpc.Server
	//用于处理客户端请求的方法在服务端尚未实现的情况。当客户端请求调用服务端的某个方法时，如果服务端没有实现该方法，服务端将会调用 Unimplemented 函数
	UnimplementedUserServiceInterfaceServer
}
type RequestBuffer struct {
	//Ctx     context.Context
	TargetServer string
	Request      MessageRequest
}

func AddNewMessage(req RequestBuffer) {
	MsgSendChannel <- req
}
func sendRequest2(req RequestBuffer) {
	var server UserServiceServer
	var ok bool
	if server, ok = ServerMap[req.TargetServer]; !ok {
		println("服务器未连接")
		return
	}
	if ServerMap[req.TargetServer].Client == nil {
		println("服务器未连接 Client为空")
		return
	}
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	stream, err := server.Client.NewNotify(ctx)
	if stream == nil {
		println("stream 流服务器已断开 服务器未连接")
		return
	}

	if err != nil {
		LogUtils.LogError("failed to call YourMethod: %v", err)
		return
	}
	nReq := &NewMessageRequest{OrderId: req.Request.OrderId,
		Header:     req.Request.Header,
		ServerName: req.Request.ServerName,
		EncodeType: req.Request.EncodeType,
		Body:       req.Request.Body,
	}
	if err = stream.Send(nReq); err != nil {
		LogUtils.LogError("Error sending message: %v", err)
	}
	//LogUtils.LogInfo("Sent message to server: %v", req)
	err = stream.CloseSend()
	if err != nil {
		LogUtils.LogError("Error closing stream: %v", err)
	}
	return
	//_, err = stream.Recv()
	//if err == io.EOF {
	//	LogUtils.LogError("Server closed stream")
	//	return
	//}
}

func (s *UserServiceServer) getOrderSize() (orderSize int64) {
	return s.orderSize
}

func (s *UserServiceServer) NewNotify(stream UserServiceInterface_NewNotifyServer) error {
	for {
		select {
		case <-stream.Context().Done():
			// Client has closed the stream.
			return stream.Context().Err()
		default:
			// Stream is still open.
		}
		req, err := stream.Recv()
		if err != nil {
			return fmt.Errorf("error receiving stream: %v", err)
		}
		//log.Printf("Received message from client: %v", req)
		MsgChannel <- RequestBuffer{
			TargetServer: "",
			Request: MessageRequest{
				req.Header,
				req.ServerName,
				req.OrderId,
				req.EncodeType,
				req.Body,
			}}
		s.orderSize++
		//resp := &ServiceMessageResponse{
		//	SendStatus:   200,
		//	SendUserId:   123,
		//	SendUserName: "John",
		//	SendOrderId:  req.OrderId,
		//}
		//
		//if err = stream.Send(resp); err != nil {
		//	return fmt.Errorf("error sending stream: %v", err)
		//}
	}
}

//非流式rpc
//func (s *UserServiceServer) NewNotify(ctx context.Context, request *NewMessageRequest) (*ServiceMessageResponse, error) {
//	MsgChannel <- RequestBuffer{
//		MessageRequest{
//			request.Header,
//			request.ServerName,
//			request.OrderId,
//			request.EncodeType,
//			request.Body,
//		}}
//	s.orderSize++
//	return &ServiceMessageResponse{SendStatus: 1, SendOrderId: request.OrderId, SendUserName: request.ServerName}, nil
//}

func (s *UserServiceServer) mustEmbedUnimplementedUserServiceInterfaceServer() {

}

func (u *UserServiceServer) release() {
	QuitChannel <- true
	close(MsgChannel)
	close(QuitChannel)
	u.server.GracefulStop()
}

// startServiceNet 初始化启动服务
func sendRequest(msg chan RequestBuffer, quit chan bool) {
	for {
		select {
		case data := <-msg:
			//启动业务函数go程
			go sendRequest2(data)
		case <-quit:
			return
		}
	}

}
func (u *UserServiceServer) StartServiceNet(addr string, f func(chan RequestBuffer, chan bool), channelLen int64) (ret bool) {
	MsgChannel = make(chan RequestBuffer, channelLen)     //消息接收缓存
	QuitChannel = make(chan bool)                         //退出所有go程
	MsgSendChannel = make(chan RequestBuffer, channelLen) //消息发送缓存
	ServerMap = make(map[string]UserServiceServer)
	for i := 0; i < 10; i++ {
		go f(MsgChannel, QuitChannel)               //解析函数
		go sendRequest(MsgSendChannel, QuitChannel) //发送函数
	}
	var err error
	u.Listen, err = net.Listen("tcp", addr) // 创建监听
	if err != nil {
		LogUtils.LogError("gRPC监听失败:", err)
	}
	u.server = grpc.NewServer()                                        // 创建grpc服务
	RegisterUserServiceInterfaceServer(u.server, &UserServiceServer{}) // 注册服务
	go func() {
		err := u.server.Serve(u.Listen)
		if err != nil {

		}
	}() // 启动监听
	return true
}

func (u *ServerClient) Connect(serverName string, targetServer []string) {
	// 创建 gRPC 连接
	conn, err := grpc.DialContext(
		context.Background(),
		strings.Join(targetServer, ","),
		grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"round_robin"}`),
		grpc.WithInsecure(),
	)
	if err != nil {
		log.Fatalf("failed to connect: %v", err)
	}
	//defer conn.Close()

	// 创建 gRPC 客户端
	Client := NewUserServiceInterfaceClient(conn)

	Ctx, CancelFunc := context.WithTimeout(context.Background(), 8*time.Second)

	statusServer := UserServiceServer{Client: Client, Ctx: Ctx, CancelFunc: CancelFunc}

	ServerMap[serverName] = statusServer
	//defer u.CancelFunc()

	// 测试发送 gRPC 请求
	//req := &NewMessageRequest{}
	//res, err := u.client.NewNotify(u.ctx, req)
	//if err != nil {
	//	log.Fatalf("failed to call YourMethod: %v", err)
	//}
	//log.Printf("response: %v", res)
}
